#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <atomic>
#include <random>
#include <iomanip>
#include "logger.hpp"

namespace mag
{
    ////////////////////////////////
    ///生成唯一ID
    ///////////////////////////////
    std::string uuid()
    {
        // 1. 生成6个0~255之间的随机数字(1字节-转换为16进制字符)--生成12位16进制字符
        std::random_device rd;  // 实例化设备随机数对象-用于生成设备随机数
        std::mt19937 generator(rd());  // 以设备随机数为种子，实例化伪随机数对象
        std::uniform_int_distribution<int> distribution(0, 255);  // 限定数据范围

        std::stringstream ss;
        for(int i =0; i<6;++i)
        {
            if (i == 2) ss << "-";  // 每2个随机数后插入一个“-”符号，格式为XX-XX-XX
            ss << std::setw(2) << std::setfill('0') << std::hex << distribution(generator);
        }
        ss<<"-";
        // 2. 通过一个静态变量生成一个2字节的编号数字--生成4位16进制数字字符
        static std::atomic<short> idx(0);  // 通过静态原子变量生成序号（保证ID唯一）
        short tmp = idx.fetch_add(1);  // 获取当前值并递增
        ss << std::setw(4) << std::setfill('0') << std::hex << tmp;
        return ss.str();  // 返回最终的唯一ID
    }

    ////////////////////////////////
    ///生成验证码
    ///////////////////////////////
    std::string vcode()
    {
        std::random_device rd;  // 实例化设备随机数对象-用于生成设备随机数
        std::mt19937 generator(rd());  // 以设备随机数为种子，实例化伪随机数对象
        std::uniform_int_distribution<int> distribution(0, 9);  // 限定数据范围

        std::stringstream ss;
        for (int i = 0; i < 4; i++) {
            ss << distribution(generator);  // 每次生成0~9的数字，并拼接成验证码
        }
        return ss.str();  // 返回最终的4位数字验证码 
    }

    ////////////////////////////////
    ///文件的读取
    ///////////////////////////////
    bool readFile(const std::string &filename, std::string &body) 
    {
            // 实现读取一个文件的所有数据，放入body中
            std::ifstream ifs(filename, std::ios::binary | std::ios::in);  // 以二进制方式打开文件
            if (ifs.is_open() == false) {
                LOG_ERROR("打开文件 {} 失败！", filename);
                return false;  // 打开文件失败
            }
            ifs.seekg(0, std::ios::end);  // 跳转到文件末尾
            size_t flen = ifs.tellg();  // 获取当前偏移量（文件大小）
            ifs.seekg(0, std::ios::beg);  // 跳转到文件起始
            body.resize(flen);  // 调整body的大小以容纳文件内容
            ifs.read(&body[0], flen);  // 读取文件内容到body
            if (ifs.good() == false) {
                LOG_ERROR("读取文件 {} 数据失败！", filename);
                ifs.close();
                return false;  // 读取失败
            }
            ifs.close();
            return true;  // 文件读取成功
    }

    ////////////////////////////////
    ///文件的写入
    ///////////////////////////////
    bool writeFile(const std::string &filename, const std::string &body) 
    {
        // 实现将body中的数据，写入filename对应的文件中
        std::ofstream ofs(filename, std::ios::out | std::ios::binary | std::ios::trunc);  // 打开文件，清空文件内容
        if (ofs.is_open() == false) {
            LOG_ERROR("打开文件 {} 失败！", filename);
            return false;  // 打开文件失败
        }
        ofs.write(body.c_str(), body.size());  // 写入body中的数据
        if (ofs.good() == false) {
            LOG_ERROR("写入文件 {} 数据失败！", filename);
            ofs.close();
            return false;  // 写入失败
        }
        ofs.close();
        return true;  // 文件写入成功
    }
}